
module PNEngine
  class ExecutionLog < ActiveRecord::Base
    include Resource::InstanceMethods
    extend Resource::ClassMethods
    
    has_many :transition_modes, :as => :execution_container
    belongs_to :case
  
 
    def get_last_modes
      #modes that don't appear as a predecessor don't have successors => at end of list
      not_last = []
      transition_modes.each do |mode|
        not_last = not_last + mode.get_preceding_modes
      end
      modes = transition_modes - not_last.uniq
      modes
    end
    
    
    def roll_back(modified_token)
      sensitive_modes = modified_token.depending_transition_modes
      p "Depending modes: #{sensitive_modes.collect{|m| m.id}.join(',')}"
      last_modes = get_last_modes
      rollback_done = false
      while !rollback_done
        last_modes.each do |mode|
          p "Undo needed for #{mode.id}?: #{undo_possible_and_needed?(mode, sensitive_modes)}"
          if undo_possible_and_needed?(mode, sensitive_modes)
            mode.undo
            last_modes.delete(mode)
            last_modes = last_modes + mode.get_preceding_modes
          end  
        end 
        # continue while there is at least one mode that can & needs to be undone
        rollback_done = true unless last_modes.collect{|mode| undo_possible_and_needed?(mode, sensitive_modes)}.include?(true)
      end
    end

    def undo_possible_and_needed?(mode, affected_modes)
      mode.undo_possible? && has_as_ancestor?(mode, affected_modes)
    end
    
    def has_as_ancestor?(mode, affected_modes)
      return true if affected_modes.include?(mode)
      modes = [mode]
      mode_found = false
      while (!mode_found && !modes.empty?)
        curr_mode = modes.first
        pre_modes = curr_mode.get_preceding_modes #mode.get_preceding_modes #
        #is any of the affected modes included in the preceding modes?
        mode_found = affected_modes.collect{|a_mode| pre_modes.include?(a_mode)}.include?(true)
        modes.delete(curr_mode)
        modes = modes + pre_modes
      end
      return mode_found
    end
    
  end #class
end #module
